#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <map>
#include <stdlib.h>
#include <lineages.h>
#include <algorithm>
#include <stdio.h>
#include <sstream>
#include <math.h>
#include <time.h>
#include <shared.h>

using namespace std;

int fitnessType;
int robustType;
int disturbType;
void loadRealLineages(string file,vector<int> & terTypes,vector<string> & terLineages);
void outputLineages(string file,const vector<int> cellTypes,const vector<string> cellLineages);
void verticalEvol(const vector<int> & termTypes,vector<string> &resLineages,const vector<double> & depth2DivRate);
void horizontalEvol(const Lineages &realLineages, vector<string> &resLineages, int popSize, int gen, double mutRate);
void horizontalEvol2(const Lineages &realLineages, vector<string> &resLineages, int popSize, int gen, double mutRate);
bool startWith(string str1, string str2); // is str1 start with str2?
void generateRandomLineageTopology(int numTerm, vector<string> res);

int main(int argc, char *argv[])
{
    vector<int> termTypes;
    vector<string> termLineages;
    string currentRoot;
    vector<int> subTermTypes;
    vector<string> subTermLineages;
    map<int, int>::iterator it;
    string tmpStr;
    double realComplexity,realRobustness;
    double subComplexity,subRobustness;

    string realLineagesFile = argv[1];
    fitnessType = atoi(argv[2]);
    robustType = atoi(argv[3]);
    disturbType = atoi(argv[4]);

    loadRealLineages(realLineagesFile,termTypes,termLineages);
    Lineages realLin(termTypes,termLineages);

    //vector<string> rndTopo;
    //generateRandomLineageTopology(termTypes.size(),rndTopo);
    realLin.getDepthStat();
    realComplexity = realLin.complexity();
    realRobustness = realLin.robustness(disturbType,robustType);

    cout << "Parameters: " << realLineagesFile;
    cout << " ; FitnessType(" << fitnessType;
    cout << ") ; RobustType(" << robustType << ")";
    cout << endl;

    cout << "Lineage Name\tComplexity\tRobustness\tMax depth\tMean depth\tS.D. depth\tfitness";
    for(it = realLin.totalTermType2Count.begin(); it!=realLin.totalTermType2Count.end(); it++)
    {
        cout << "\t" << "TermType(" << it->first <<")";
    }
    cout << endl;
    cout << realLineagesFile << "\t" << realComplexity << "\t" << realRobustness << "\t" << realLin.depthMax << "\t";
    cout << realLin.depthMean << "\t" << realLin.depthSD << "\t" << fitness(fitnessType,realRobustness,realComplexity);
    for(it = realLin.totalTermType2Count.begin(); it!=realLin.totalTermType2Count.end(); it++)
    {
        cout << "\t" << it->second ;
    }
    cout << endl;

    for(unsigned int i=realLin.termLineages.size(); i<realLin.allLineages.size(); i++)
    {
        subTermLineages.clear();
        subTermTypes.clear();
        currentRoot = realLin.allLineages[i];
        for(unsigned int j=0; j<termLineages.size(); j++)
        {
            if(startWith(termLineages[j],currentRoot))
            {
                tmpStr = termLineages[j];
                tmpStr = tmpStr.substr(currentRoot.length(),tmpStr.length() - currentRoot.length());
                subTermLineages.push_back(tmpStr);
                subTermTypes.push_back(termTypes[j]);
            }
        }
        Lineages subLin(subTermTypes,subTermLineages);

        subLin.getDepthStat();
        subComplexity = subLin.complexity();
        subRobustness = subLin.robustness(disturbType,robustType);

        cout << currentRoot << "\t" << subComplexity << "\t" << subRobustness << "\t" << subLin.depthMax << "\t";
        cout << subLin.depthMean << "\t" << subLin.depthSD << "\t" << fitness(fitnessType,subRobustness,subComplexity);
        for(it = realLin.totalTermType2Count.begin(); it!=realLin.totalTermType2Count.end(); it++)
        {
            cout << "\t" << subLin.totalTermType2Count[it->first];
        }
        cout << endl;
    }
}
